# -*- coding: utf-8 -*-

from hlm.node import *

from ip.softmem import NodeSoftmem
from ip.erunner import NodeERunner, ChannelERunnerSoftmem
from ip.mrunner import NodeMRunner
from ip.alu import NodeAlu, ChannelAlu
from ip.and_gate import NodeAndGate
from ip.fabrics import ChannelLoadFabric


class NodePeer(Node):
    def initialize(self, params: ObjectDict) -> None:
        params.peer_id: int
        params.softmem_size: int
        params.num_of_main_memory: int
        params.num_of_alu: int
        params.multiplexer: int
        params.total_peers: int
        params.base_ptrs: 'List.int'
        # Save the node property.
        self.const.peer_id = params.peer_id
        # 1x Softmem node that connects to all ALUs
        self.node.softmem = self.node_create(
            NodeSoftmem,
            {'softmem_size': params.softmem_size,
             'num_of_main_memory': params.num_of_main_memory,
             'num_of_alu': params.num_of_alu,
             'multiplexer': params.multiplexer})
        # 1x E-Runner node
        self.node.erunner = self.node_create(
            NodeERunner,
            {'num_of_alu': params.num_of_alu,
             'peer_id': params.peer_id,
             'total_peers': params.total_peers,
             'base_ptrs': params.base_ptrs})
        # 1x M-Runner node.
        self.node.mrunner = self.node_create(
            NodeMRunner,
            {'peer_ids': [params.peer_id]})
        # Nx ALUs
        self.node.alus = [self.node_create(NodeAlu) for _ in range(params.num_of_alu)]
        # 1x And-gate node for halt detection.
        self.node.halt_detect = self.node_create(
            NodeAndGate,
            {'num_of_ports': params.num_of_alu + 1})

        # Create bypass nano op receiver port.
        self.port.nano_op_receiver = self.port_bypass(self.node.erunner.port.nano_op_receiver)
        # Create bypass memory controller port.
        self.port.memory_receivers = self.port_bypass(self.node.softmem.port.memory_receivers)
        self.port.memory_senders = self.port_bypass(self.node.softmem.port.memory_senders)
        # Connect the internal nodes.
        #  Softmem <=> ALUs
        for ii in range(params.num_of_alu):
            ChannelAlu.connect(self.node.softmem.port.alu_senders[ii],
                               self.node.alus[ii].port.receiver)
        #  ERunner => Softmem
        for ii in range(params.num_of_alu):
            ChannelERunnerSoftmem.connect(self.node.erunner.port.softmem_senders[ii],
                                          self.node.softmem.port.erunner_receivers[ii])
        #  MRunner <=> Softmem
        ChannelLoadFabric.connect(self.node.mrunner.port.message_out,
                                  self.node.softmem.port.mrunner_receiver)
        ChannelLoadFabric.connect(self.node.softmem.port.mrunner_sender,
                                  self.node.mrunner.port.message_in)
        #  Softmem => Halt
        for ii in range(params.num_of_alu):
            self.node.softmem.port.halt_alu[ii].connect(self.node.halt_detect.port.and_ins[ii])
        #  MRunner => Halt
        self.node.mrunner.port.halt.connect(self.node.halt_detect.port.and_ins[-1])

        # Bypass the M-Runner.
        self.port.chain_out = self.port_bypass(self.node.mrunner.port.chain_out)
        self.port.chain_in = self.port_bypass(self.node.mrunner.port.chain_in)
        # Bypass the Halt detection.
        self.port.halt = self.port_bypass(self.node.halt_detect.port.and_out)